package com.android.cs4274;

//import static digit.client.LogIn.DIGIT_CACHE_DIR;
//import static digit.client.LogIn.DIGIT_DIR;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.message.BasicHeader;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.apache.http.protocol.HTTP;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONTokener;

//import digit.client.ImageHandler.FlushedInputStream;

import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnCancelListener;
import android.net.http.AndroidHttpClient;
import android.os.AsyncTask;
import android.util.Log;

/**
 * APIs for interacting with the PHP server
 * 
 * @author Jian Zhu
 *
 */
public class DigitClientAPI extends AsyncTask<String, Void, Integer> {
	public static final String SERVER_URL = "http://137.132.145.205/digit/service.php";
	public static final String FILE_UPLOAD_URL = "http://137.132.145.205/digit/fileUploader.php";
	public static final int CONNECTION_TIME_OUT = 8000;
	public static final int SOCKET_TIME_OUT = 10000;
	
	public static final int STATUS_OK = 1;
	public static final int STATUS_NOT_FOUND = 2;
	public static final int STATUS_DUPLICATE = 3;
	public static final int STATUS_FAIL = 4;
	public static final int STATUS_ERROR = 5;
	
	private Context context;
	private String message;
	private ProgressDialog dialog;
	
	private JSONObject result;
	
	private static final String LOG_TAG = "DigitClientAPI";
	
	public DigitClientAPI() {}
	
    public DigitClientAPI(Context context, String message) {
        this.context = context;
        this.message = message;
    }
    
    protected JSONObject getResult() {
    	return result;
    }

    protected void onPreExecute() {
    	if (message != null) {
    		dialog = ProgressDialog.show(context,"",message);
    		dialog.setCancelable(true);
    		dialog.setOnCancelListener(new OnCancelListener() {
				@Override
				public void onCancel(DialogInterface arg0) {
					cancel(true);
				}
    		});
    	}
    }  
    protected Integer doInBackground(String... args) {
    	String command = args[0];
    	try {
    		JSONObject request = new JSONObject();
    		request.put("command",command);
	    	if (command.equals("registerAccount")) {
	    		request.put("account",args[1]);
	    		request.put("password",args[2]);
	    		request.put("nick",args[3]);
	    		request.put("image",args[4]);
	    		request.put("last_sync",args[5]);
	    	}
	    	else if (command.equals("login")) {
	    		request.put("account",args[1]);
	    		request.put("password",args[2]);
	    	}
	    	else if (command.equals("retrievePassword")) {
	    		request.put("account",args[1]);
	    	}
	    	else if (command.equals("getAccountInfo")) {
	    		request.put("account",args[1]);
	    	}
	    	else if (command.equals("retrieveDigs")) { 
	    		request.put("latitude",args[1]);
	    		request.put("longitude",args[2]);
	    		request.put("radius",args[3]);
	    		request.put("type",args[4]);
	    		request.put("availability",args[5]);
	    		request.put("keywords",args[6]);
	    	}
	    	else if (command.equals("retrievePersonMarks")) { 
	    		request.put("account",args[1]);
	    		request.put("start_date",args[2]);
	    		request.put("end_date",args[3]);
	    	}
	    	else if (command.equals("retrievePersonTreasures")) { 
	    		request.put("account",args[1]);
	    		request.put("start_date",args[2]); 
	    		request.put("end_date",args[3]);
	    	}
	    	else if (command.equals("updatePersonAvatar")) {
	    		request.put("account",args[1]);
	    		request.put("image",args[2]);
	    	}
	    	else if (command.equals("createMark")) {
	    		request.put("id",args[1]);
	    		request.put("entity",args[2]);
	    		request.put("latitude",args[3]);
	    		request.put("longitude",args[4]);
	    		request.put("account",args[5]);
	    		request.put("content",args[6]);
	    		request.put("images",args[7]);
	    		request.put("date",args[8]); 
	    		request.put("last_sync",args[9]);
	    		request.put("popularity",args[10]);
	    		request.put("rank",args[11]);
	    	}
	    	else if (command.equals("createTreasure")) {
	    		request.put("id",args[1]);
	    		request.put("entity",args[2]);
	    		request.put("latitude",args[3]);
	    		request.put("longitude",args[4]);
	    		request.put("account",args[5]);
	    		request.put("content",args[6]);
	    		request.put("images",args[7]);
	    		request.put("url",args[8]);
	    		request.put("phone",args[9]);
	    		request.put("sms",args[10]);
	    		request.put("access",args[11]);
	    		request.put("start_date",args[12]);
	    		request.put("end_date",args[13]);
	    		request.put("create_date",args[14]);
	    		request.put("last_sync",args[15]);
	    		request.put("popularity",args[16]);
	    		request.put("rank",args[17]);
	    	}
	    	else if (command.equals("deleteTreasure")) {
	    		request.put("id",args[1]);
	    	}
	    	else if (command.equals("updateTreasure")) {
	    		request.put("id",args[1]);
	    		request.put("latitude",args[2]);
	    		request.put("longitude",args[3]);
	    		request.put("last_sync",args[4]);
	    	}
	    	else if (command.equals("syncDigs")) {
	    		request.put("id",args[1]);
	    	}
	    	
	    	if (!isCancelled()) {
		    	String resultString = postRequest(request);
		    	Log.i(LOG_TAG,resultString);
		    	if (resultString != null) {
		    		Log.i(LOG_TAG,resultString);
		    		result = (JSONObject) new JSONTokener(resultString).nextValue();
		    		int status = result.getInt("status");
		    		if (status == STATUS_OK) {
		    			if (command.equals("registerAccount") && args[4] != "-1" && !isCancelled()) 
			    			uploadImage(args[1],args[4]);
		    			//else if (command.equals("getAccountInfo") && !isCancelled()) 
		    				//saveImage(result.getString("image"));
		    			else if (command.equals("updatePersonAvatar") && !isCancelled())
		    				uploadImage(args[1],args[2]);
		    			else if (command.equals("createMark") || command.equals("createTreasure")) {
		    				if (!args[7].equals("-1")) {
		    					JSONArray images = (JSONArray) new JSONTokener(args[7]).nextValue();
		    					for (int i = 0; i < images.length() && !isCancelled(); i++) {
		    						String image = images.getString(i);
		    						if (!image.equals("-1"))
		    							uploadImage(args[5],image);
		    					}
		    				}
		    			}
		    		}
		    		return status;
	    		}
	    	}
    	}
    	catch (JSONException e) {
    		Log.w("DigitClientTask","JSON error",e);
	    }
    	catch (Exception e) {
    		Log.w("DigitClientTask","Runtim error",e);
	    }
	    
    	return STATUS_ERROR;
    }
    
    private String postRequest(JSONObject request) {
    	HttpClient client = AndroidHttpClient.newInstance("Android");
    	HttpParams httpParameters = client.getParams();
    	HttpConnectionParams.setConnectionTimeout(httpParameters,CONNECTION_TIME_OUT);
    	HttpConnectionParams.setSoTimeout(httpParameters,SOCKET_TIME_OUT);
        HttpPost postRequest = new HttpPost(SERVER_URL);
    	try {
    		StringEntity se = new StringEntity(request.toString());  
            se.setContentEncoding(new BasicHeader(HTTP.CONTENT_TYPE,"application/json"));
            postRequest.setEntity(se);
            HttpResponse response = client.execute(postRequest);
            int statusCode = response.getStatusLine().getStatusCode();
            if (statusCode != HttpStatus.SC_OK) {
                Log.w(LOG_TAG,"Error " + statusCode);
                return null;
            }

            HttpEntity entity = response.getEntity();
            if (entity != null) {
                InputStream inputStream = null;
                try {
                    inputStream = entity.getContent();
                    
                    BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));
                    StringBuilder sb = new StringBuilder();
                    String line = null;
                    while ((line = br.readLine()) != null) 
                      sb.append(line + "\n");

                    br.close();
                    
                    return sb.toString();
                } 
                finally {
                    if (inputStream != null) 
                        inputStream.close();

                    entity.consumeContent();
                }
            }
    	}
    	catch (IOException e) {
    		postRequest.abort();
            Log.w(LOG_TAG,"I/O error while retrieving data from " + SERVER_URL,e);
        } 
        catch (IllegalStateException e) {
        	postRequest.abort();
            Log.w(LOG_TAG,"Incorrect URL: " + SERVER_URL);
        } 
        catch (Exception e) {
        	postRequest.abort();
            Log.w(LOG_TAG,"Error while retrieving data from " + SERVER_URL,e);
        } 
        finally {
            if (client instanceof AndroidHttpClient) 
                ((AndroidHttpClient) client).close();
        }
        
        return null;
    }
    
    private void uploadImage(String account, String filePath) {
    	String lineEnd = "\r\n";
    	String twoHyphens = "--";
    	String boundary = "*****";
    	
		try {
			InputStream is = null;
			if (android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED)) {
				if (filePath.startsWith("file"))
					filePath = filePath.substring(7);
				
				is = new FileInputStream(new File(filePath));
			}
		
			if (is != null) {
				URL connectURL = new URL(FILE_UPLOAD_URL);
				HttpURLConnection conn = (HttpURLConnection) connectURL.openConnection();
				conn.setDoInput(true);
				conn.setDoOutput(true);
				conn.setUseCaches(false);
				
				// Use a post method.
				conn.setRequestMethod("POST");
				conn.setRequestProperty("Connection", "Keep-Alive");
				conn.setRequestProperty("Content-Type", "multipart/form-data;boundary="+boundary);
				
				DataOutputStream dos = new DataOutputStream(conn.getOutputStream());
				String fileName = filePath.substring(filePath.lastIndexOf('/')+1);
				
				dos.writeBytes(twoHyphens + boundary + lineEnd);
				dos.writeBytes("Content-Disposition: form-data; name=\"uploadImage\"; fileName=\"" + account + "+" + fileName + "\"" + lineEnd);
				dos.writeBytes(lineEnd);
				// create a buffer of maximum size
				int bufferSize = Math.min(is.available(),1024);
				byte[] buffer = new byte[bufferSize];
				
				int bytesRead = is.read(buffer,0,bufferSize);
				while (bytesRead > 0) {
		    		dos.write(buffer,0,bufferSize);
		    		bufferSize = Math.min(is.available(),1024);
		    		bytesRead = is.read(buffer,0,bufferSize);
				}
				
				dos.writeBytes(lineEnd);
				dos.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd);
				is.close();
				dos.flush();
				dos.close();
				
				InputStream inputStream = conn.getInputStream();
				if (inputStream != null) {
					BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
					StringBuilder sb = new StringBuilder();
	                String line = null;
	
	                while ((line = br.readLine()) != null) 
	                  sb.append(line + "\n");
	
	                br.close();
					//Log.i(LOG_TAG,sb.toString());
					inputStream.close();
				}
			}
		}
		catch (IOException e) {
            Log.w(LOG_TAG,"I/O Exception while uploading image " + filePath);
        } 
	} 
    /*
    private void saveImage(String url) {
    	if (!android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED) || url.equals("-1")) 
    		return;
    	
        File dir = new File(android.os.Environment.getExternalStorageDirectory(),DIGIT_DIR);
        dir.mkdir();
        String fileName = url.substring(url.lastIndexOf('/')+1);
        File f = new File(dir,fileName);
        if(!f.exists()) { 
        	dir = new File(android.os.Environment.getExternalStorageDirectory(),DIGIT_CACHE_DIR);	
        	dir.mkdir();
        	f = new File(dir,fileName);
        	if (!f.exists()) { // save to cache dir
        		// download from web
        		final HttpClient client = AndroidHttpClient.newInstance("Android");
                final HttpGet getRequest = new HttpGet(url);

                try {
                    HttpResponse response = client.execute(getRequest);
                    final int statusCode = response.getStatusLine().getStatusCode();
                    if (statusCode != HttpStatus.SC_OK) {
                        Log.w(LOG_TAG, "Error " + statusCode + " while retrieving bitmap from " + url);
                        return;
                    }

                    final HttpEntity entity = response.getEntity();
                    if (entity != null) {
                        InputStream inputStream = null;
                        try {
                        	inputStream = entity.getContent();
                            // return BitmapFactory.decodeStream(inputStream);
                            // Bug on slow connections, fixed in future release.
                            // bitmap = BitmapFactory.decodeStream(new FlushedInputStream(inputStream));
                        	FlushedInputStream is = new FlushedInputStream(inputStream);
                            OutputStream os = new FileOutputStream(f);
                            byte[] buffer = new byte[1024];
                		    int read;
                		    while((read = is.read(buffer)) != -1)
                		    	os.write(buffer,0,read);
                            
                            os.flush();
                            is.close();
                            os.close();
                        } 
                        finally {
                            if (inputStream != null) 
                            	inputStream.close();
                            
                            entity.consumeContent();
                        }
                    }
                } 
                catch (IOException e) {
                    getRequest.abort();
                    Log.w(LOG_TAG,"I/O error while retrieving bitmap from " + url,e);
                } 
                catch (IllegalStateException e) {
                    getRequest.abort();
                    Log.w(LOG_TAG,"Incorrect URL: " + url);
                } 
                catch (Exception e) {
                    getRequest.abort();
                    Log.w(LOG_TAG,"Error while retrieving bitmap from " + url,e);
                } 
                finally {
                    if (client instanceof AndroidHttpClient) 
                        ((AndroidHttpClient) client).close();
                }
        	}
        } 
    }
    
    */
    protected void onPostExecute(Integer resultCode) {
    	if (dialog != null && dialog.isShowing())
            dialog.dismiss();
    }
}
